package com.ibeeking.found.cop.b.rest.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.gson.JsonObject;
import com.ibeeking.found.common.utils.UserUtils;
import com.ibeeking.found.cop.b.rest.service.*;
import com.ibeeking.found.cop.service.common.dos.CopEmployeeDO;
import com.ibeeking.found.cop.service.common.dos.MsgMassMessageDO;
import com.ibeeking.found.cop.service.common.dos.MsgMessageTaskDO;
import com.ibeeking.found.cop.service.common.enums.MqSyncOperatorTypeEnum;
import com.ibeeking.found.cop.service.common.enums.WxCpMessageAssignStatusEnum;
import com.ibeeking.found.cop.service.common.enums.WxCpMessageSendWayEnum;
import com.ibeeking.found.cop.service.common.param.MqSyncCopParam;
import com.ibeeking.found.cop.service.common.param.MsgMessageTaskParam;
import com.ibeeking.found.cop.service.common.query.MsgMessageTaskPageQuery;
import com.ibeeking.found.cop.service.common.query.MsgMessageTaskQuery;
import com.ibeeking.found.cop.service.common.vo.MsgMessageTaskVO;
import com.ibeeking.found.cop.service.mapper.CopEmployeeMapper;
import com.ibeeking.found.cop.service.mapper.MsgMassMessageMapper;
import com.ibeeking.found.cop.service.mapper.MsgMessageTaskMapper;
import com.ibeeking.found.id.GenerateId;
import com.ibeeking.nematos.core.utils.SpringBeanUtil;
import com.ibeeking.nematos.exception.BusinessException;
import com.ibeeking.nematos.log.utils.LogUtils;
import com.ibeeking.nematos.utils.bean.BeanUtil;
import com.ibeeking.nematos.utils.data.Collections3;
import com.ibeeking.nematos.utils.date.DateUtil;
import com.ibeeking.nematos.utils.id.IdGenerator;
import com.ibeeking.nematos.utils.json.JsonUtils;
import me.chanjar.weixin.common.enums.WxType;
import me.chanjar.weixin.common.error.WxError;
import me.chanjar.weixin.cp.api.WxCpExternalContactService;
import me.chanjar.weixin.cp.api.WxCpService;
import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl;
import me.chanjar.weixin.cp.bean.external.contact.WxCpGroupMsgListResult;
import me.chanjar.weixin.cp.bean.external.contact.WxCpGroupMsgResult;
import me.chanjar.weixin.cp.config.WxCpConfigStorage;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Consts;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.CloseableHttpClient;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.IOException;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @ClassName MsgMessageTaskServiceImpl
 * @Description
 * @Author ibeeking
 * @Date 2021-01-27 18:50
 **/
@Service
public class MsgMessageTaskServiceImpl extends ServiceImpl<MsgMessageTaskMapper, MsgMessageTaskDO> implements IMsgMessageTaskService {

    DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    @Resource
    private MsgMassMessageMapper msgMassMessageMapper;

    @Resource
    private MsgMessageTaskMapper msgMessageTaskMapper;

    @Resource
    private CopEmployeeMapper copEmployeeMapper;

    @Resource
    private IMsgMassMessageService msgMassMessageServiceImpl;

    @Resource
    private IMsgMessageTaskSenderService msgMessageTaskSenderServiceImpl;

    @Resource
    private IWxOpenService wxOpenServiceImpl;

    @Resource
    private IMqService mqServiceImpl;

    @Override
    public List<MsgMessageTaskVO> list(MsgMessageTaskQuery query) {
        List<MsgMessageTaskDO> entityDOS = msgMessageTaskMapper.selectList(new LambdaQueryWrapper<MsgMessageTaskDO>()
                .eq(query.getId() != null, MsgMessageTaskDO::getId, query.getId())
                .eq(StringUtils.isNotBlank(query.getChatType()), MsgMessageTaskDO::getChatType, query.getChatType())
                .eq(query.getSendWay() != null, MsgMessageTaskDO::getSendWay, query.getSendWay())
                .eq(query.getMessageId() != null, MsgMessageTaskDO::getMessageId, query.getMessageId())
                .eq(query.getSenderId() != null, MsgMessageTaskDO::getSenderId, query.getSenderId())
                .eq(StringUtils.isNotBlank(query.getRtnMsgId()), MsgMessageTaskDO::getRtnMsgId, query.getRtnMsgId())
                .orderByDesc(MsgMessageTaskDO::getSendTime)
        );
        List<MsgMessageTaskVO> entityVOS =JsonUtils.jsonToList(entityDOS, MsgMessageTaskVO.class);
        entityVOS.forEach(x -> {
            x.setSendWayDesc(WxCpMessageSendWayEnum.getDescByCode(x.getSendWay()));
        });
        return entityVOS;
    }

    @Override
    public Page<MsgMessageTaskVO> pageList(MsgMessageTaskPageQuery pageQuery) {
        LambdaQueryWrapper<MsgMessageTaskDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(pageQuery.getId() != null, MsgMessageTaskDO::getId, pageQuery.getId())
                .eq(StringUtils.isNotBlank(pageQuery.getChatType()), MsgMessageTaskDO::getChatType, pageQuery.getChatType())
                .eq(pageQuery.getSendWay() != null, MsgMessageTaskDO::getSendWay, pageQuery.getSendWay())
                .eq(pageQuery.getMessageId() != null, MsgMessageTaskDO::getMessageId, pageQuery.getMessageId())
                .eq(pageQuery.getSenderId() != null, MsgMessageTaskDO::getSenderId, pageQuery.getSenderId())
                .eq(StringUtils.isNotBlank(pageQuery.getRtnMsgId()), MsgMessageTaskDO::getRtnMsgId, pageQuery.getRtnMsgId())
                .orderByDesc(MsgMessageTaskDO::getSendTime);
        Page<MsgMessageTaskDO> entityDOPages = msgMessageTaskMapper.selectPage(new Page<MsgMessageTaskDO>(pageQuery.getPageNum(), pageQuery.getPageSize()), wrapper);
        Page<MsgMessageTaskVO> entityVOPages = BeanUtil.convertPage(entityDOPages, MsgMessageTaskVO.class);
        entityVOPages.getRecords().forEach(f ->{
            f.setSendWayDesc(WxCpMessageSendWayEnum.getDescByCode(f.getSendWay()));
        });
        return entityVOPages;
    }

    @Override
    public MsgMessageTaskVO view(Long id) {
        MsgMessageTaskDO entityDO = msgMessageTaskMapper.selectById(id);
        if(entityDO == null) throw new BusinessException("没有查到相关记录！");
        MsgMessageTaskVO entityVO = BeanUtil.convertBean(entityDO, MsgMessageTaskVO.class);
        if(entityVO != null) {
            entityVO.setSendWayDesc(WxCpMessageSendWayEnum.getDescByCode(entityVO.getSendWay()));
        }
        return entityVO;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean add(MsgMessageTaskParam param) {
        MsgMessageTaskDO entityDO = BeanUtil.convertBean(param, MsgMessageTaskDO.class);
        entityDO.setId(GenerateId.generateId());
        return msgMessageTaskMapper.insert(entityDO) > 0;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean sendMessageNotify(Long messageId) {
        String tenantId = UserUtils.getTenantId();
        MqSyncCopParam mqParam = new MqSyncCopParam();
        mqParam.setOperType(MqSyncOperatorTypeEnum.COP_SYNC_MESSAGE_TASK_NOTIFY.getCode());
        mqParam.setTenantId(Long.valueOf(tenantId));
        mqParam.setId(messageId);
        mqServiceImpl.sendSyncToWxTaskMessage(mqParam);
        return true;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Integer syncMessageNotifySenderTaskToWxCp(Integer tenantId,Long messageId){
        if(messageId == null) throw new BusinessException("发送任务获取消息参数msgId为空");
        MsgMassMessageDO messageDO = msgMassMessageMapper.selectById(messageId);
        if(messageDO == null) throw new BusinessException("通过msgId获得的消息数据为空!");
        String rtnMsgId = messageDO.getRtnMsgId();

        Boolean result = askWxCpToNotifySender(tenantId.toString(), rtnMsgId);
        if(result) {
            return 1;
        }else{
            return 0;
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Integer syncMessageSenderTaskStatusFromWxCp(Long messageId){
        String tenantId = UserUtils.getTenantId();
        if(messageId == null) throw new BusinessException("发送任务获取消息参数msgId为空");
        MsgMassMessageDO messageDO = msgMassMessageMapper.selectById(messageId);
        if(messageDO == null) throw new BusinessException("通过msgId获得的消息数据为空!");
        String rtnMsgId = messageDO.getRtnMsgId();
        try {
            WxCpService wxCpService = wxOpenServiceImpl.getWxCpService(Long.valueOf(tenantId));
            WxCpConfigStorage wxCpConfigStorage = wxCpService.getWxCpConfigStorage();
            if (wxCpConfigStorage == null) {
                throw new BusinessException("获取企微服务失败!");
            }
            WxCpExternalContactService wxCpExternalContactService = wxCpService.getExternalContactService();
            if (wxCpExternalContactService == null) throw new BusinessException("获取企微服务外部联系人服务!");

            String nexCursor = null;
            do {
                WxCpGroupMsgResult wxCpGroupMsgResult = wxCpExternalContactService.getGroupMsgResult(rtnMsgId, 800, nexCursor);
                LogUtils.info("====process wxCpGroupMsgResult:{}====", JsonUtils.toJsonStr(wxCpGroupMsgResult));
                if (wxCpGroupMsgResult != null) {
                    nexCursor = wxCpGroupMsgResult.getNextCursor();
                    List<WxCpGroupMsgResult.ExternalContactGroupMsgDetailInfo> msgDetailInfoList = wxCpGroupMsgResult.getDetailList();
                    if (Collections3.isNotEmpty(msgDetailInfoList)) {
                        for(WxCpGroupMsgResult.ExternalContactGroupMsgDetailInfo msgDetailInfo:msgDetailInfoList){
                            String userid = msgDetailInfo.getUserId();
                            String chatId = msgDetailInfo.getChatId();
                            Integer status = msgDetailInfo.getStatus();
                            String externalUserid= msgDetailInfo.getExternalUserId();
                            Long sendTime = msgDetailInfo.getSendTime();
                        }
                    }
                }
            }while(nexCursor == null);
            return 1;
        } catch (Exception ex) {
            LogUtils.error("获取企微服务失败!" + ex);
            return 0;
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean syncMessageSendRecordFromWxCp(Integer tenantId, String chatType, String beginDate, String endDate){
        try {
            WxCpService wxCpService = wxOpenServiceImpl.getWxCpService(tenantId.longValue());
            WxCpConfigStorage wxCpConfigStorage = wxCpService.getWxCpConfigStorage();
            if (wxCpConfigStorage == null) {
                throw new BusinessException("获取企微服务失败!");
            }
            WxCpExternalContactService wxCpExternalContactService = wxCpService.getExternalContactService();
            if (wxCpExternalContactService == null) throw new BusinessException("获取企微服务外部联系人服务!");
            LocalDateTime beginDateTime = DateUtil.strToLocalDateTime(beginDate);
            LocalDateTime  endDateTime = DateUtil.strToLocalDateTime(endDate);
            if(beginDateTime!=null && endDateTime!=null) {
                List<String> allMessageCodes = new ArrayList<>();
                List<MsgMassMessageDO> needInsertMessageDOS = new ArrayList<>();
                List<MsgMassMessageDO> needUpdateMessageDOS = new ArrayList<>();
                List<CopEmployeeDO> copEmployeeDOS = copEmployeeMapper.selectList(new LambdaQueryWrapper<>());
                Map<String, Long> copEmployeeNameMaps = Collections3.isNotEmpty(copEmployeeDOS) ? copEmployeeDOS.stream().collect(Collectors.toMap(CopEmployeeDO::getEmployeeCode, CopEmployeeDO::getId, (o, n) -> n)) : null;

                List<MsgMassMessageDO> allMessageDOS = msgMassMessageMapper.selectList(new LambdaQueryWrapper<MsgMassMessageDO>());
                Map<String, MsgMassMessageDO> allMessageCodeMap = Collections3.isNotEmpty(allMessageDOS) ? allMessageDOS.stream().collect(Collectors.toMap(MsgMassMessageDO::getRtnMsgId, x -> x, (o, n) -> n)) : null;
                int days = DateUtil.days(beginDateTime, endDateTime);
                for (long i = 0; i * 29 < days; i++) {
                    Long beginDateTimeLong = Timestamp.valueOf(beginDateTime.plusDays(i * 29)).getTime();
                    Long endDateTimeLong = 0L;
                    if (days - (i * 29) <= 29) {
                        endDateTimeLong = Timestamp.valueOf(beginDateTime.plusDays(days - i * 29)).getTime();
                    } else {
                        endDateTimeLong = Timestamp.valueOf(beginDateTime.plusDays((i + 1) * 29)).getTime();
                    }
                    String nextCursor = null;
                    do {
                        WxCpGroupMsgListResult wxCpGroupMsgListResult = wxCpExternalContactService.getGroupMsgListV2(chatType,new Date(beginDateTimeLong), new Date(endDateTimeLong), null, null, null, null);
                        LogUtils.info("====process WxCpGroupMsgListResult:{}====", JsonUtils.toJsonStr(wxCpGroupMsgListResult));
                        if (wxCpGroupMsgListResult != null) {
                            nextCursor = wxCpGroupMsgListResult.getNextCursor();
                            List<WxCpGroupMsgListResult.ExternalContactGroupMsgInfo> ExternalContactGroupMsgInfoList = wxCpGroupMsgListResult.getGroupMsgList();
                            for (WxCpGroupMsgListResult.ExternalContactGroupMsgInfo msgInfo : ExternalContactGroupMsgInfoList) {
                                String messageCode = msgInfo.getMsgId();
                                Long createTime = msgInfo.getCreateTime();
                                Integer createType = msgInfo.getCreateType();
                                me.chanjar.weixin.cp.bean.external.msg.Text contentText = msgInfo.getText();
                                if(allMessageCodeMap!=null && allMessageCodeMap.containsKey(messageCode)){
                                    MsgMassMessageDO updateMessageDO = allMessageCodeMap.get(messageCode);
                                    updateMessageDO.setRtnMsgId(messageCode);
                                    if(createTime!=null){
                                        updateMessageDO.setBuidTime(DateUtil.longToLocalDateTime(Long.valueOf(createTime)));
                                    }
                                    updateMessageDO.setBuildType(createType);
                                    if(StringUtils.isNotEmpty(msgInfo.getCreator())) {
                                        updateMessageDO.setBuilderCode(msgInfo.getCreator());
                                        updateMessageDO.setBuilderId(copEmployeeNameMaps!=null?copEmployeeNameMaps.get(msgInfo.getCreator()):null);
                                    }

                                    List<me.chanjar.weixin.cp.bean.external.msg.Attachment> attachmentList = msgInfo.getAttachments();

                                    updateMessageDO.setModifyTime(LocalDateTime.now());
                                    needUpdateMessageDOS.add(updateMessageDO);
                                }else{
                                    MsgMassMessageDO msgMassMessageDO = new MsgMassMessageDO();
                                    Long momentId = IdGenerator.getId();
                                    msgMassMessageDO.setSendCycle(1);
                                    msgMassMessageDO.setChatType(chatType);
                                    msgMassMessageDO.setSendStatus(WxCpMessageAssignStatusEnum.MESSAGE_ASSIGN_STATUS_ASSIGNED.getCode());
                                    msgMassMessageDO.setSendWay(WxCpMessageSendWayEnum.MESSAGE_SEND_WAY_NOW.getCode());
                                    msgMassMessageDO.setId(momentId);
                                    msgMassMessageDO.setRtnMsgId(messageCode);
                                    if(createTime!=null){
                                        msgMassMessageDO.setBuidTime(DateUtil.longToLocalDateTime(Long.valueOf(createTime)));
                                        msgMassMessageDO.setSendTime(DateUtil.longToLocalDateTime(Long.valueOf(createTime)));
                                    }
                                    msgMassMessageDO.setBuildType(msgInfo.getCreateType());
                                    if(StringUtils.isNotEmpty(msgInfo.getCreator())) {
                                        msgMassMessageDO.setBuilderCode(msgInfo.getCreator());
                                        msgMassMessageDO.setBuilderId(copEmployeeNameMaps!=null?copEmployeeNameMaps.get(msgInfo.getCreator()):null);
                                    }

                                    me.chanjar.weixin.cp.bean.external.msg.Text momentText = msgInfo.getText();
                                    if(momentText!=null){
                                        String momentContent = momentText.getContent();
                                        if(StringUtils.isNotEmpty(momentContent)) {
                                            msgMassMessageDO.setContent(momentContent);
                                            msgMassMessageDO.setName(StringUtils.substring(momentContent,0,10));
                                        }
                                    }
                                    List<me.chanjar.weixin.cp.bean.external.msg.Attachment> attachmentList = msgInfo.getAttachments();
                                    msgMassMessageDO.setCreateTime(LocalDateTime.now());
                                    msgMassMessageDO.setModifyTime(LocalDateTime.now());
                                    needInsertMessageDOS.add(msgMassMessageDO);
                                }
                            }
                        }else{
                            nextCursor = null;
                        }
                    } while (nextCursor == null);
                }
                if(Collections3.isNotEmpty(needInsertMessageDOS)){
                    msgMassMessageMapper.insertBatchSomeColumn(needInsertMessageDOS);
                }
                if(Collections3.isNotEmpty(needUpdateMessageDOS)){
                    msgMassMessageServiceImpl.updateBatch(needUpdateMessageDOS);
                }
                if(Collections3.isNotEmpty(allMessageCodes)){
                    msgMessageTaskSenderServiceImpl.syncMessageTaskSenderListFromWxCp(tenantId, chatType, allMessageCodes);

                }

            }
            return true;
        } catch (Exception e) {
            throw new BusinessException("获取企微服务失败!");
        }
    }


    private Boolean askWxCpToNotifySender(String tenantId, String messageCode){
        try {
            String getFollowUserUrl = "/cgi-bin/externalcontact/remind_groupmsg_send?access_token=%s";
            WxCpServiceImpl wxCpService = (WxCpServiceImpl)wxOpenServiceImpl.getWxCpService(Long.valueOf(tenantId));
            WxCpConfigStorage wxCpConfigStorage = wxCpService.getWxCpConfigStorage();
            if (wxCpConfigStorage == null) {
                throw new BusinessException("获取企微服务失败!");
            }
            String url = String.format(wxCpConfigStorage.getApiUrl(getFollowUserUrl),wxCpConfigStorage.getAccessToken());
            try {
                HttpPost httpPost = new HttpPost(url);
                JsonObject jsonObject = new JsonObject();
                jsonObject.addProperty("msgid", messageCode);
                StringEntity entity = new StringEntity(jsonObject.toString(), Consts.UTF_8);
                httpPost.setEntity(entity);

                String resultContent;
                try (CloseableHttpClient httpClient = wxCpService.getRequestHttpClient();
                     CloseableHttpResponse response = httpClient.execute(httpPost)) {
                    resultContent = new BasicResponseHandler().handleResponse(response);
                } finally {
                    httpPost.releaseConnection();
                }
                WxError error = WxError.fromJson(resultContent, WxType.CP);
                if (error.getErrorCode() != 0) {
                    LogUtils.error("提醒成员群发任务失败，原因：{}",error.getErrorMsg());
                    return false;
                }else{
                    return true;
                }
            } catch (IOException e) {
                LogUtils.error("提醒成员群发任务失败，原因：{}",e);
                return false;
            }
        }catch(Exception ex){
            return false;
        }
    }

     private IMsgMessageTaskService getBean(){
         return SpringBeanUtil.getBean(MsgMessageTaskServiceImpl.class);
     }
}
